﻿namespace Mercury.ParticleEngine
{
    using System;
    using System.Diagnostics.Contracts;

    /// <summary>
    /// Defines a random number geenrator which uses the RANDU algorithm to generate random values.
    /// The RANDU algorithm does not generate evenly distributed random values, but it is fast and
    /// it may be adequate in some scenarios.
    /// </summary>
    public sealed class RanduRandomGenerator : IRandomGenerator
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="RanduRandomGenerator"/> class.
        /// </summary>
        public RanduRandomGenerator()
            : this(1)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="RanduRandomGenerator"/> class.
        /// </summary>
        /// <param name="seed">The initial seed value, must be greater than zero.</param>
        /// <exception cref="T:System.ArgumentOutOfRangeException">
        /// Thrown if the value passed to the <paramref name="seed"/> parameter is not greater
        /// than zero.
        /// </exception>
        public RanduRandomGenerator(Int32 seed)
        {
            Contract.Requires<ArgumentOutOfRangeException>(seed > 0);

            _state = seed;
        }

        private Int32 _state;

        /// <summary>
        /// Gets the next random integer value.
        /// </summary>
        /// <returns>A random positive integer.</returns>
        public Int32 NextInteger()
        {
            return _state = ((_state << 16) + (_state << 1) + _state) & 0x7FFFFFFF;
        }

        /// <summary>
        /// Gets the next random single value.
        /// </summary>
        /// <returns>A random single value between 0 and 1.</returns>
        public Single NextSingle()
        {
            return NextInteger() / (Single)Int32.MaxValue;
        }
    }
}